package ether

import (
	"MPCBot/global"
	"MPCBot/handle/contract"
	"bytes"
	"context"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math"
	"math/big"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
)

type PriceData struct {
	Elapsed       string `json:"elapsed"`
	Last          string `json:"last"`
	QuoteVolume   string `json:"quoteVolume"`
	BaseVolume    string `json:"baseVolume"`
	HighestBid    string `json:"highestBid"`
	High24hr      string `json:"high24hr"`
	LowestAsk     string `json:"lowestAsk"`
	Low24hr       string `json:"low24hr"`
	PercentChange string `json:"percentChange"`
	Result        string `json:"result"`
}

func BigintToFloat64(bigints *big.Int) (floatv float64) {
	bigintss := bigints
	ip := big.NewInt(1000000000000)
	var bigIntStr = bigintss.Div(bigintss, ip).String()
	limitInt, _ := strconv.ParseInt(bigIntStr, 10, 64)
	floatf, _ := strconv.ParseFloat(fmt.Sprintf("%.6f", float64(limitInt)/1000000), 64)

	return floatf
}

func BigintToFloat64ByDecimal(bigints *big.Int, decimal uint8) (floatv float64) {
	if decimal < 6 {
		return 0
	}
	bigintss := bigints
	ip := big.NewInt(int64(math.Pow(10, float64(decimal-6))))
	var bigIntStr = bigintss.Div(bigintss, ip).String()
	limitInt, _ := strconv.ParseInt(bigIntStr, 10, 64)
	floatf, _ := strconv.ParseFloat(fmt.Sprintf("%.6f", float64(limitInt)/1000000), 64)

	return floatf
}

func CentToFloat64(bigints *big.Int) (floatv float64) {
	bigintss := bigints
	ip := big.NewInt(1)
	var bigIntStr = bigintss.Div(bigintss, ip).String()
	limitInt, _ := strconv.ParseInt(bigIntStr, 10, 64)
	floatf, _ := strconv.ParseFloat(fmt.Sprintf("%.6f", float64(limitInt)/100), 64)

	return floatf
}

func AppendWei(intnumber int, wei int) *big.Int {

	var bt bytes.Buffer
	bt.WriteString(strconv.Itoa(intnumber))
	for i := 1; i <= wei; i++ {
		bt.WriteString("0")
	}
	result := new(big.Int)
	result, ok := result.SetString(bt.String(), 10)
	if !ok {
		panic("error")
	}

	fmt.Println(result.String())
	return result
}

func GetTokenDeciaml(client *ethclient.Client, tokenAdr string) uint8 {
	tokenContract, err := contract.NewToken(common.HexToAddress(tokenAdr), client)
	if err != nil {
		global.Log.Error("getTokenPairInfo: error：%v", err.Error())
		return 0
	}
	deciaml, _ := tokenContract.Decimals(nil)
	if deciaml == 0 {
		deciaml = 18
	}
	return deciaml
}

func GetTokenName(client *ethclient.Client, tokenAdr string) string {
	tokenContract, err := contract.NewToken(common.HexToAddress(tokenAdr), client)
	if err != nil {
		global.Log.Error("getTokenPairInfo: error：%v", err.Error())
		return ""
	}
	tokenName, _ := tokenContract.Symbol(nil)
	return strings.ToLower(tokenName)
}

func GetTokenInfo(client *ethclient.Client, tokenAdr string) (decimal uint8, symbol string) {
	tokenContract, err := contract.NewToken(common.HexToAddress(tokenAdr), client)
	if err != nil {
		global.Log.Error("getTokenPairInfo: error：%v", err.Error())
		return 0, ""
	}
	decimal, _ = tokenContract.Decimals(nil)
	if decimal == 0 {
		decimal = 18
	}
	symbol, _ = tokenContract.Symbol(nil)
	return
}

func EncodePacked(input ...[]byte) []byte {
	return bytes.Join(input, nil)
}

func GetTokenPrice(tokenName string) float64 {
	var gateioprice float64 = 0.00
	var priceData PriceData
	if tokenName == "usdt" {
		return 1.00
	}
	if tokenName == "usdc" {
		return 1.00
	}
	pairToken0_USDT := tokenName + "_usdt"

	// Skip certificate validation
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	httpClient := &http.Client{
		Transport: tr,
		Timeout:   time.Second * 5,
	}

	var resp *http.Response
	resp, err := httpClient.Get("https://data.gateapi.io/api2/1/ticker/" + pairToken0_USDT)
	if err != nil {
		global.Log.Error("GetGateioPrice error：%v", err.Error())
		return 0.00
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		global.Log.Error("GetGateioPrice error：%v", err.Error())
		return 0.00
	}
	if err := json.Unmarshal([]byte(body), &priceData); err == nil {
		gateioprice, _ = strconv.ParseFloat(priceData.Last, 64)
	}
	global.Log.Info("====> gate.io [%v] last price is %v", tokenName, gateioprice)

	return gateioprice
}

func GetEtherClient(rpcUrls []string) (rpcUrlsNew []string, client *ethclient.Client) {
	var err error
	f := func() bool {
		client, err = ethclient.Dial(rpcUrls[0])
		if err != nil {
			global.Log.Error("====>  GetEthClient rpcurl[%v] ethclient: error：%v", rpcUrls[0], err.Error())
			rpcUrls = rpcUrls[1:]
			return false
		}
		_, err = client.ChainID(context.Background())
		if err != nil {
			global.Log.Error("====>  GetEthClient rpcurl[%v] ethclient: error：%v", rpcUrls[0], err.Error())
			rpcUrls = rpcUrls[1:]
			return false
		}
		return true
	}
	for {
		if f() || len(rpcUrls) == 0 {
			break
		}
	}
	rpcUrlsNew = rpcUrls
	return rpcUrlsNew, client
}
